package jcer.test;

import gnu.getopt.Getopt;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.List;

import jcer.core.Packet;

public class EchoTaskAb {
	static class Worker implements Runnable {
		String host = "127.0.0.1";
		int port = 3261;
		int maxRequests = 10000;

		int fail = 0;
		int succ = 0;

		@Override
		public void run() {
			try {
				SocketChannel socket = SocketChannel.open();
				socket.connect(new InetSocketAddress(host, port));
				for (int i = 0; i < maxRequests; i++) {
					try {
						execute(socket);
						succ++;
					} catch (Exception e) {
						fail++;
					}
					addComplateRequest(1);
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		public void execute(SocketChannel socket) throws Exception {
			int bodyLen = 4;
			int count = 2;
			List<String> msgs = new ArrayList<String>();
			for (int i = 1; i <= count; i++) {
				String msg = "Hello Cer" + i;
				msgs.add(msg);
				bodyLen += msg.getBytes("utf-8").length + 4 + 4 + 4;
			}
			ByteBuffer reqBuf = ByteBuffer.allocate(Packet.getHeaderLen()
					+ bodyLen);
			byte[] versionStream = new byte[10];
			byte[] tmp = "jcer1.0.0".getBytes();
			System.arraycopy(tmp, 0, versionStream, 0, tmp.length);

			reqBuf.put(versionStream);// version
			reqBuf.putInt(bodyLen);// bodyLen
			reqBuf.putInt(1);// cmd
			reqBuf.putInt(0xff);// magic

			reqBuf.putInt(msgs.size());// count
			int taskNum = 1;
			for (String msg : msgs) {
				reqBuf.putInt(msg.getBytes("utf-8").length + 8);
				reqBuf.putInt(1);
				reqBuf.putInt(taskNum++);
				reqBuf.put(msg.getBytes("utf-8"));
			}

			reqBuf.position(0);
			socket.write(reqBuf);

			Packet packet = new Packet();
			ByteBuffer resBuf = ByteBuffer.allocate(Packet.getHeaderLen());
			socket.read(resBuf);
			resBuf.position(0);
			packet.unpackHeader(resBuf);

			resBuf = ByteBuffer.allocate(packet.bodyLen);
			while (resBuf.remaining() > 0) {
				socket.read(resBuf);
			}
			resBuf.position(0);
			packet.unpackBody(resBuf);
			responseLen = resBuf.limit() + Packet.getHeaderLen();
		}

	}

	static int complatedRequest;
	static int totalRequest;
	static int responseLen;

	public static synchronized void addComplateRequest(int n) {
		complatedRequest += n;
		if (complatedRequest % ((int) (totalRequest / 10)) == 0) {
			System.out.println("finished " + complatedRequest + " requests");
		}
	}

	public static void main(String[] args) throws Exception {
		// default config
		String host = "127.0.0.1";
		int port = 3261;
		int threadNum = 20;
		int maxRequests = 10000;

		// args
		int c;
		Getopt opt = new Getopt("jcer", args, "l:p:c:n:");

		while ((c = opt.getopt()) != -1) {
			switch (c) {
			case 'l':
				host = opt.getOptarg();
				break;
			case 'p':
				port = Integer.parseInt(opt.getOptarg());
				break;
			case 'c':
				threadNum = Integer.parseInt(opt.getOptarg());
				break;
			case 'n':
				maxRequests = Integer.parseInt(opt.getOptarg());
				break;
			}
		}

		totalRequest = maxRequests;
		complatedRequest = 0;

		long start = System.currentTimeMillis();
		Worker[] workers = new Worker[threadNum];
		Thread[] threads = new Thread[threadNum];
		for (int i = 0; i < threadNum; i++) {
			workers[i] = new Worker();
			workers[i].host = host;
			workers[i].port = port;
			workers[i].maxRequests = maxRequests / threadNum;

			threads[i] = new Thread(workers[i]);
			threads[i].start();
		}

		for (int i = 0; i < threadNum; i++) {
			threads[i].join();
		}
		
		int succ = 0;
		int fail = 0;
		for (int i = 0; i < threadNum; i++) {
			succ = workers[i].succ;
			fail = workers[i].fail;
		}
		
		long end = System.currentTimeMillis();
		long cost = (end - start);
		double reqsPerSec = maxRequests;
		if (cost > 0) {
			reqsPerSec = (double) maxRequests / cost * 1000;
		}
		System.out.println("\n\nperformance report:");
		System.out.println("--------------------------------------------");
		System.out.println("Server Hostname:        " + host);
		System.out.println("Server Port:            " + port);
		System.out.println("Response Length:        " + responseLen);
		System.out.println("succ/fail:              " + succ + "/" + fail);
		System.out.println("Requests per second:    " + (int) reqsPerSec
				+ " [#/sec] (mean)");
		System.out.println("Time per request:       " + (double) cost
				/ maxRequests + " [ms] (mean)");
		System.out.println("Transfer rate:          " + responseLen
				* maxRequests / cost + " [Kbytes/sec] received");

	}
}
